package scalab.core.component

import scala.collection.immutable.{Set, HashSet}
import scalab.core.dependencies.{Dependency, HardDependency, SoftDependency}

trait Task extends ExecutableComponent{

  //TODO
  //var fileDeps: HashMap<Task, FileDependency extends FileResource>


	def execute(destinationDir: String): Boolean

	//develop alternative methods (String*, Iterable)
  def built(path: String): Component = {
		//info("Built file " + path)
    submit(HardDependency(path))
  }

	def built(paths: Iterable[String]): Component = {
		submit(paths map {HardDependency(_)})
	}

	def mayBuild(path: String): Component = {
		//info("May build file " + path)
    submit(SoftDependency(path))
  }

	//make it public for cache development?
	import java.io.File
	private[core] var productDirectory: String = "." + File.separator //crossplatform => use workingDirectory?
	def productDir: String = productDirectory
	override def productDirs: List[String] = List(productDirectory)

	/*private[core] def triggerExecutionStarted = executionStartedListeners foreach { l =>
		l.triggerEvent(event.ExecutionStarted(this))
	}

	private[core] def triggerExecutionFinished = executionFinishedListeners foreach { l =>
		l.triggerEvent(event.ExecutionFinished(this))
	}*/

	private[core] def exec: Boolean = {

		reset
		/*import scala.collection.immutable.TreeSet //empty component's output
		out.setDeps(TreeSet.empty(Dependency.dependency2ordered _))
		filesRelations.clear */

		//import scalab.utils.FileUtils
		val lacks: List[Dependency] = lackingSources

		if(lacks.isEmpty){
			getCache.run(this)
		}
		else{
			error((lacks map {d => d.canonicalPath}).mkString("Missing needed recource(s):\n\t", "\n\t", ""))
			false
		}
	}

	final def locallyUpToDate(products: Set[Resource]): Boolean = {
		val cache = getCache
		val (onlyHits, upToDateProds) = cache.getRunProducts(this, this.sources)
		onlyHits && 
			cache.resourcesHash(products) == cache.resourcesHash(
				if(upToDateProds.isEmpty)Nil
				else upToDateProds.get
			)
	}

	Task.allTasks = Task.allTasks + this
}

object Task{
	private[core] var allTasks: Set[Task] = HashSet.empty[Task]
	def getAll: Set[Task] = allTasks
}
